package util;

import com.serotonin.modbus4j.BatchRead;
import com.serotonin.modbus4j.BatchResults;
import com.serotonin.modbus4j.ModbusFactory;
import com.serotonin.modbus4j.ModbusMaster;
import com.serotonin.modbus4j.code.DataType;
import com.serotonin.modbus4j.exception.ErrorResponseException;
import com.serotonin.modbus4j.exception.ModbusInitException;
import com.serotonin.modbus4j.exception.ModbusTransportException;
import com.serotonin.modbus4j.ip.IpParameters;
import com.serotonin.modbus4j.locator.BaseLocator;

/**
 * modbus4j读取数据
 * */
public class Modbus4jReadUtils {
    /**
     * 工厂
     */
    static ModbusFactory modbusFactory;

    static {
        if (modbusFactory == null) {
            modbusFactory = new ModbusFactory();
        }
    }

    /**
     * 获取master
     */
    public static ModbusMaster getMaster() throws ModbusInitException {
        IpParameters params = new IpParameters();
        params.setHost("192.168.2.188");
        params.setPort(502);
        // TCP协议
        ModbusMaster master = modbusFactory.createTcpMaster(params, false);
        master.init();
        return master;
    }

    /**
     * 读取[01 Coil Status 0x]类型 开关数据
     *
     * @param slaveId 从机id，一般连一个的情况下，默认是1
     * @param offset 读取地址，从零开始，如果实际地址是1的话，这里填0
     */
    public static Boolean readCoilStatus(int slaveId, int offset) throws ModbusInitException, ErrorResponseException, ModbusTransportException {
        BaseLocator<Boolean> loc = BaseLocator.coilStatus(slaveId, offset);
        Boolean value = getMaster().getValue(loc);
        return value;
    }

    /**
     * 读取[02 Input Status 1x]类型 开关数据
     *
     * @param slaveId 从机id，一般连一个的情况下，默认是1
     * @param offset 读取地址，从零开始，如果实际地址是1的话，这里填0
     */
    public static Boolean readInputStatus(int slaveId, int offset) throws ModbusInitException, ErrorResponseException, ModbusTransportException {
        BaseLocator<Boolean> loc = BaseLocator.inputStatus(slaveId, offset);
        Boolean value = getMaster().getValue(loc);
        return value;
    }

    /**
     * 读取[03 Holding Register 2x]模拟量数据
     *
     * @param slaveId 从机id，一般连一个的情况下，默认是1
     * @param offset 读取地址，从零开始，如果实际地址是1的话，这里填0
     */
    public static Number readHoldingRegister(int slaveId, int offset, int dataType) throws ModbusInitException, ErrorResponseException, ModbusTransportException {
        BaseLocator<Number> loc = BaseLocator.holdingRegister(slaveId, offset, dataType);
        Number value = getMaster().getValue(loc);
        return value;
    }

    /**
     * 读取[04 Input Register 3x]类型 模拟量数据
     *
     * @param slaveId 从机id，一般连一个的情况下，默认是1
     * @param offset 读取地址，从零开始，如果实际地址是1的话，这里填0
     */
    public static Number readInputRegisters(int slaveId, int offset, int dataType) throws ModbusInitException, ErrorResponseException, ModbusTransportException {
        BaseLocator<Number> loc = BaseLocator.inputRegister(slaveId, offset, dataType);
        Number value = getMaster().getValue(loc);
        return value;
    }

    /**
     * 批量读取使用方法
     */
    public static void batchRead() throws ModbusInitException, ErrorResponseException, ModbusTransportException {
        BatchRead<Integer> batch = new BatchRead<>();
        batch.addLocator(0, BaseLocator.coilStatus(1, 0));
        batch.addLocator(1, BaseLocator.coilStatus(1, 1));
        batch.addLocator(2, BaseLocator.coilStatus(1, 2));
        batch.addLocator(3, BaseLocator.coilStatus(1, 3));
        batch.addLocator(4, BaseLocator.coilStatus(1, 4));
        batch.addLocator(5, BaseLocator.coilStatus(1, 5));
        batch.addLocator(6, BaseLocator.coilStatus(1, 6));
        batch.addLocator(7, BaseLocator.coilStatus(1, 7));
        ModbusMaster master = getMaster();
        batch.setContiguousRequests(false);
        BatchResults<Integer> results = master.send(batch);
        System.out.println("批量读取测试：");
        System.out.println(results.getValue(0));
        System.out.println(results.getValue(1));
        System.out.println(results.getValue(2));
        System.out.println(results.getValue(3));
        System.out.println(results.getValue(4));
        System.out.println(results.getValue(5));
        System.out.println(results.getValue(6));
        System.out.println(results.getValue(7));
    }

    public static void main(String[] args) {
        try {
            // 01测试
//            Boolean v011 = readCoilStatus(1, 0);
//            Boolean v012 = readCoilStatus(1, 1);
//            Boolean v013 = readCoilStatus(1, 6);
//            System.out.println("[01 Coil Status 0x]类型 开关类型 测试：");
//            System.out.printf("v011: %s \r\n", v011);
//            System.out.printf("v012: %s \r\n", v012);
//            System.out.printf("v013: %s \r\n", v013);
            // 02测试
//            Boolean v021 = readInputStatus(1, 0);
//            Boolean v022 = readInputStatus(1, 1);
//            Boolean v023 = readInputStatus(1, 2);
//            System.out.println("[02 Input Status 1x]类型 开关数据 测试：");
//            System.out.printf("v021: %s \r\n", v021);
//            System.out.printf("v022: %s \r\n", v022);
//            System.out.printf("v023: %s \r\n", v023);
            // 03测试 读取整数
            Number v031 = readHoldingRegister(1, 0, DataType.TWO_BYTE_INT_SIGNED);
            // 03测试 读取浮点数
//            Number v032 = readHoldingRegister(1, 3, DataType.FOUR_BYTE_FLOAT);
            System.out.println("[03 Holding Register 2x]模拟量数据 测试：");
            System.out.printf("v031: %s \r\n", v031);
//            System.out.printf("v032: %s \r\n", v032);
            // 04测试
//            Number v041 = readInputRegisters(1, 0, DataType.FOUR_BYTE_FLOAT);
//            Number v042 = readInputRegisters(1, 2, DataType.FOUR_BYTE_FLOAT);
//            System.out.println("[04 Input Register 3x]类型 模拟量数据 测试：");
//            System.out.printf("v041: %s \r\n", v041);
//            System.out.printf("v042: %s \r\n", v042);
            // 批量读取
//            batchRead();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
